package com.typhoon.spring_shiro.service.shiro;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 请求上下文,绑定在当前线程中，当请求处理完成之后，将清除该ThreadLocal中的数据
 * 
 * @author Ternence
 * @date 2016年10月8日
 */
public abstract class RequestContext {

	private static final ThreadLocal<Map<Object, Object>> resources = new InheritableThreadLocalMap<Map<Object, Object>>();
	
	private static final Logger log = LoggerFactory.getLogger(RequestContext.class);
	
	public static final String SESSION_DATA = "__SESSION_DATA";

	public static Object get(Object key) {
		if (log.isTraceEnabled()) {
			String msg = "get() - in thread ["
					+ Thread.currentThread().getName() + "]";
			log.trace(msg);
		}

		Object value = getValue(key);
		if ((value != null) && log.isTraceEnabled()) {
			String msg = "Retrieved value of type ["
					+ value.getClass().getName() + "] for key [" + key + "] "
					+ "bound to thread [" + Thread.currentThread().getName()
					+ "]";
			log.trace(msg);
		}
		return value;
	}

	public static void put(Object key, Object value) {
		if (key == null) {
			throw new IllegalArgumentException("key cannot be null");
		}

		if (value == null) {
			remove(key);
			return;
		}

		resources.get().put(key, value);

		if (log.isTraceEnabled()) {
			String msg = "Bound value of type [" + value.getClass().getName()
					+ "] for key [" + key + "] to thread " + "["
					+ Thread.currentThread().getName() + "]";
			log.trace(msg);
		}
	}

	public static Object remove(Object key) {
		Object value = resources.get().remove(key);

		if ((value != null) && log.isTraceEnabled()) {
			String msg = "Removed value of type [" + value.getClass().getName()
					+ "] for key [" + key + "]" + "from thread ["
					+ Thread.currentThread().getName() + "]";
			log.trace(msg);
		}

		return value;
	}

	public static void remove() {
		resources.remove();
	}
	
	private static Object getValue(Object key) {
        return resources.get().get(key);
    }
	
	private static final class InheritableThreadLocalMap<T extends Map<Object, Object>> extends InheritableThreadLocal<Map<Object, Object>> {
        protected Map<Object, Object> initialValue() {
            return new HashMap<Object, Object>();
        }

        @SuppressWarnings({"unchecked"})
        protected Map<Object, Object> childValue(Map<Object, Object> parentValue) {
            if (parentValue != null) {
                return (Map<Object, Object>) ((HashMap<Object, Object>) parentValue).clone();
            } else {
                return null;
            }
        }
    }
}
